package cn.elwy.rcp.ui.dialog;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import cn.elwy.common.exception.MsgLevel;
import cn.elwy.rcp.core.model.ui.DialogInfo;
import cn.elwy.rcp.core.model.ui.DialogType;
import cn.elwy.rcp.ui.config.DialogConfigFactory;

/**
 * 所有自定义对话框的父类
 * @author huangsq
 * @version 1.0, 2013-11-20
 * @since 1.0, 2013-11-20
 */
public class BaseDialog extends CDialog {

  private static final String BASE_DIALOG = "BaseDialog";

  protected boolean lockedUI = false;
  protected boolean useCustomProgressMonitorPart = true;

  protected boolean isCreateHeade = true;
  protected boolean isCreateMonitor;

  private String message = ""; //$NON-NLS-1$
  private String errorMessage;
  private Text messageLabel;
  private Composite contents;
  private Control dialogArea;
  private Label messageImageLabel;
  private Image messageImage;
  private boolean showingError = false;

  private boolean titleImageLargest = true;

  private Image titleAreaImage;

  private String windowTitle; // 窗口标题
  private Image windowImage; // 窗口图标
  private boolean isDirty;
  private Thread thread;

  public static final String DLG_IMG_TITLE_BANNER = "dialog_title_banner_image";//$NON-NLS-1$
  public static final String DLG_IMG_MESSAGE_INFO = "dialog_messasge_info_image"; //$NON-NLS-1$
  public static final String DLG_IMG_MESSAGE_WARNING = "dialog_messasge_warning_image"; //$NON-NLS-1$
  public static final String DLG_IMG_MESSAGE_ERROR = "dialog_message_error_image"; //$NON-NLS-1$

  private String dialogId = BASE_DIALOG;
  private DialogInfo dialogInfo;

  public BaseDialog(Shell shell, String windowTitle) {
    this(shell, windowTitle, null);
  }

  /**
   * @wbp.parser.constructor
   */
  public BaseDialog(Shell parentShell, String windowTitle, Image windowImage) {
    super(parentShell);
    this.windowTitle = windowTitle;
    this.windowImage = windowImage;
  }

  protected Control createContents(Composite parent) {
    contents = new Composite(parent, SWT.NONE);
    contents.setLayoutData(new GridData(GridData.FILL_BOTH));
    GridLayout gl_contents = new GridLayout(1, false);
    gl_contents.verticalSpacing = 0;
    gl_contents.marginWidth = 0;
    gl_contents.marginHeight = 0;
    gl_contents.horizontalSpacing = 0;
    contents.setLayout(gl_contents);

    applyDialogFont(contents);
    initializeDialogUnits(contents);

    applyDialogFont(contents);

    if (isCreateHeade) {
      createHeaderArea(contents);
    }

    dialogArea = createDialogArea(contents);

    buttonBar = super.createButtonBar(contents);

    return contents;
  }

  protected void createHeaderArea(Composite parent) {
    Composite headerArea = new Composite(parent, SWT.NONE);
    headerArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
    GridLayout gl_headerArea = new GridLayout(1, false);
    gl_headerArea.verticalSpacing = 0;
    gl_headerArea.marginWidth = 0;
    gl_headerArea.marginHeight = 0;
    gl_headerArea.horizontalSpacing = 0;
    headerArea.setLayout(gl_headerArea);

    Display display = parent.getDisplay();
    Color background = JFaceColors.getBannerBackground(display);
    Color foreground = JFaceColors.getBannerForeground(display);

    headerArea.setBackgroundMode(SWT.BACKGROUND);
    headerArea.setBackground(background);

    applyDialogFont(headerArea);

    Composite titleArea = new Composite(headerArea, SWT.NONE);
    titleArea.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true, 1, 1));
    GridLayout gl_titleArea = new GridLayout(2, false);
    gl_titleArea.marginLeft = 5;
    gl_titleArea.verticalSpacing = 10;
    gl_titleArea.marginHeight = 10;
    gl_titleArea.horizontalSpacing = 0;
    titleArea.setLayout(gl_titleArea);
    GridData gd_titleArea = new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1);
    gd_titleArea.heightHint = 60;
    gd_titleArea.minimumHeight = 60;
    titleArea.setLayoutData(gd_titleArea);
    GridData gd_remarkLabel = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
    gd_remarkLabel.horizontalIndent = 12;

    messageImageLabel = new Label(titleArea, SWT.CENTER);
    GridData gd_messageImageLabel = new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1);
    gd_messageImageLabel.widthHint = 16;
    gd_messageImageLabel.minimumWidth = 16;
    messageImageLabel.setLayoutData(gd_messageImageLabel);
    messageImageLabel.setImage(JFaceResources.getImage(DLG_IMG_MESSAGE_ERROR));
    messageImageLabel.setBackground(background);

    messageLabel = new Text(titleArea, SWT.WRAP | SWT.READ_ONLY);
    messageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
    JFaceColors.setColors(messageLabel, foreground, background);
    messageLabel.setText("errorMessage"); //$NON-NLS-1$
    messageLabel.setFont(JFaceResources.getDialogFont());

    Label headerSeparator = new Label(headerArea, SWT.SEPARATOR | SWT.HORIZONTAL);
    headerSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    headerArea.setFont(JFaceResources.getDialogFont());
    initializeDialogUnits(headerArea);
  }

  protected Control createDialogArea(Composite contentCompisite) {
    Composite bodyArea = new Composite(contentCompisite, SWT.NONE);
    bodyArea.setLayout(new GridLayout(1, false));
    bodyArea.setLayoutData(new GridData(GridData.FILL_BOTH));
    applyDialogFont(bodyArea);
    return bodyArea;
  }

  protected ProgressMonitorPart createProgressMonitorPart(Composite composite, GridLayout pmlayout) {
    if (blockedHandler == null) {
      return null;
    }
    useCustomProgressMonitorPart = false;
    ProgressMonitorPart progressMonitorPart = new ProgressMonitorPart(composite, pmlayout, true) {
      String currentTask = null;

      public void setBlocked(IStatus reason) {
        super.setBlocked(reason);
        if (!lockedUI) {
          getBlockedHandler().showBlocked(getShell(), this, reason, currentTask);
        }
      }

      public void clearBlocked() {
        super.clearBlocked();
        if (!lockedUI) {
          getBlockedHandler().clearBlocked();
        }
      }

      public void beginTask(String name, int totalWork) {
        super.beginTask(name, totalWork);
        currentTask = name;
      }

      public void setTaskName(String name) {
        super.setTaskName(name);
        currentTask = name;
      }

      public void subTask(String name) {
        super.subTask(name);
        // If we haven't got anything yet use this value for more
        // context
        if (currentTask == null) {
          currentTask = name;
        }
      }
    };

    GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
    progressMonitorPart.setLayoutData(gridData);
    progressMonitorPart.setVisible(false);
    applyDialogFont(progressMonitorPart);
    return progressMonitorPart;
  }

  public void setErrorMessage(String newErrorMessage) {
    // Any change?
    if (errorMessage == null ? newErrorMessage == null : errorMessage.equals(newErrorMessage))
      return;
    errorMessage = newErrorMessage;

    // Clear or set error message.
    if (errorMessage == null) {
      if (showingError) {
        // we were previously showing an error
        showingError = false;
      }
      // show the message
      // avoid calling setMessage in case it is overridden to call
      // setErrorMessage,
      // which would result in a recursive infinite loop
      if (message == null) // this should probably never happen since
        // setMessage does this conversion....
        message = ""; //$NON-NLS-1$
      updateMessage(message);
      updateMessageImage(messageImage);
      setImageLabelVisible(messageImage != null);
    } else {
      // Add in a space for layout purposes but do not
      // change the instance variable
      String displayedErrorMessage = errorMessage; // $NON-NLS-1$
      updateMessage(displayedErrorMessage);
      if (!showingError) {
        // we were not previously showing an error
        showingError = true;
        messageImageLabel.setImage(JFaceResources.getImage(DLG_IMG_MESSAGE_ERROR));
        setImageLabelVisible(true);
      }
    }
    // layoutForNewMessage(false);
  }

  private void setImageLabelVisible(boolean visible) {
    if (messageImageLabel != null) {
      messageImageLabel.setVisible(visible);
    }
    // bottomFillerLabel.setVisible(visible);
    // leftFillerLabel.setVisible(visible);
  }

  public void setMessage(String newMessage) {
    setMessage(newMessage, MsgLevel.INFO);
  }

  public void setMessage(String newMessage, MsgLevel level) {
    Image newImage = null;
    if (newMessage != null) {
      switch (level) {
        case INFO:
          newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_INFO);
          break;
        case WARN:
          newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_WARNING);
          break;
        case ERROR:
          newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_ERROR);
          break;
      }
    }
    showMessage(newMessage, newImage);
  }

  private void showMessage(String newMessage, Image newImage) {
    if (newMessage == null) {
      newMessage = ""; //$NON-NLS-1$
    }

    // Any change?
    if (message.equals(newMessage) && messageImage == newImage) {
      return;
    }
    message = newMessage;

    // Message string to be shown - if there is an image then add in
    // a space to the message for layout purposes
    String shownMessage = message; // $NON-NLS-1$
    messageImage = newImage;
    if (!showingError) {
      // we are not showing an error
      updateMessage(shownMessage);
      updateMessageImage(messageImage);
      setImageLabelVisible(messageImage != null);
      // layoutForNewMessage(false);
    }
  }

  private void updateMessageImage(Image image) {
    if (messageImageLabel != null) {
      messageImageLabel.setImage(image);
    }
  }

  private void updateMessage(String newMessage) {
    if (messageLabel != null) {
      messageLabel.setText(newMessage);
    }
  }

  public boolean isCreateHeade() {
    return isCreateHeade;
  }

  public void setCreateHeade(boolean isCreateHeade) {
    this.isCreateHeade = isCreateHeade;
  }

  public boolean isCreateMonitor() {
    return isCreateMonitor;
  }

  public void setCreateMonitor(boolean isCreateMonitor) {
    this.isCreateMonitor = isCreateMonitor;
  }

  public Text getMessageLabel() {
    return messageLabel;
  }

  public void setMessageLabel(Text messageLabel) {
    this.messageLabel = messageLabel;
  }

  public Composite getContents() {
    return contents;
  }

  public void setContents(Composite contents) {
    this.contents = contents;
  }

  public Control getDialogArea() {
    return dialogArea;
  }

  public void setDialogArea(Control dialogArea) {
    this.dialogArea = dialogArea;
  }

  public Label getMessageImageLabel() {
    return messageImageLabel;
  }

  public void setMessageImageLabel(Label messageImageLabel) {
    this.messageImageLabel = messageImageLabel;
  }

  public Image getMessageImage() {
    return messageImage;
  }

  public void setMessageImage(Image messageImage) {
    this.messageImage = messageImage;
  }

  public boolean isShowingError() {
    return showingError;
  }

  public void setShowingError(boolean showingError) {
    this.showingError = showingError;
  }

  public boolean isTitleImageLargest() {
    return titleImageLargest;
  }

  public void setTitleImageLargest(boolean titleImageLargest) {
    this.titleImageLargest = titleImageLargest;
  }

  public Image getTitleAreaImage() {
    return titleAreaImage;
  }

  public void setTitleAreaImage(Image titleAreaImage) {
    this.titleAreaImage = titleAreaImage;
  }

  public String getMessage() {
    return message;
  }

  public String getErrorMessage() {
    return errorMessage;
  }

  // protected Control createContents(Composite parent) {
  // Composite composite1 = new Composite(parent, 0);
  // GridLayout layout = new GridLayout(1, false);
  // layout.marginHeight = 0;
  // layout.marginWidth = 0;
  // layout.verticalSpacing = 0;
  // composite1.setLayout(layout);
  // composite1.setLayoutData(new GridData(GridData.FILL_BOTH));
  // applyDialogFont(composite1);
  // initializeDialogUnits(composite1);
  // Composite composite = new Composite(composite1, SWT.NONE);
  // composite.setLayout(new FormLayout());
  // composite.setLayoutData(new GridData(GridData.FILL_BOTH));
  //
  // header = new Composite(composite, SWT.NONE);
  // header.setLayout(new FormLayout());
  //
  // FormData fd_header = new FormData();
  // fd_header.top = new FormAttachment(0);
  // fd_header.left = new FormAttachment(0);
  // fd_header.right = new FormAttachment(100);
  // header.setLayoutData(fd_header);
  //
  // footer = new Composite(composite, SWT.NONE);
  // footer.setLayout(new FormLayout());
  // FormData fd_footer = new FormData();
  // fd_footer.right = new FormAttachment(100);
  // fd_footer.bottom = new FormAttachment(100);
  // fd_footer.left = new FormAttachment(0);
  // footer.setLayoutData(fd_footer);
  //
  // body = new Composite(composite, SWT.NONE);
  // body.setLayout(new FormLayout());
  // FormData fd_body = new FormData();
  // fd_body.bottom = new FormAttachment(footer, 0, SWT.TOP);
  // fd_body.top = new FormAttachment(header, 0, SWT.BOTTOM);
  // fd_body.left = new FormAttachment(0);
  // fd_body.right = new FormAttachment(100);
  // body.setLayoutData(fd_body);
  //
  // createHeader(composite);
  // createFooter(footer);
  // createBody(body);
  //
  // initView();
  //
  // return composite;
  // }

  /** 初始化视图 */
  protected void initView() {
  }

  /** 设置窗口居中 */
  @Override
  protected Point getInitialLocation(Point initialSize) {
    if (!dialogInfo.isCenter()) {
      return new Point(dialogInfo.getX(), dialogInfo.getY());
    }
    Rectangle shellBounds = null;
    if (getParentShell() == null) {
      shellBounds = Display.getCurrent().getBounds();
    } else {
      shellBounds = getParentShell().getBounds();
    }
    Point dialogSize = initialSize;
    return new Point(shellBounds.x + (shellBounds.width - dialogSize.x) / 2,
        shellBounds.y + (shellBounds.height - dialogSize.y) / 2);
  }

  /** 设置窗口初始化大小 */
  @Override
  protected Point getInitialSize() {
    return new Point(500, 360);
  }

  @Override
  protected void configureShell(Shell newShell) {
    super.configureShell(newShell);
    if (windowImage != null) {
      newShell.setImage(windowImage);
    }
    if (windowTitle != null) {
      newShell.setText(windowTitle);
    }
  }

  @Override
  protected void setShellStyle(int newShellStyle) {
    super.setShellStyle(newShellStyle);// | SWT.DIALOG_TRIM);// | SWT.APPLICATION_MODAL);
    // SWT.BORDER //建立一个有边框但没有标题栏的窗口
    // SWT.CLOSE //建立一个只有关闭按钮的窗口
    // SWT.MIN //建立一个不能最大化的窗口
    // SWT.MAX, //建立一个可以最大化最小化的窗口
    // SWT.NO_TRIM //建立一个没有任何边界和标题栏的窗口
    // SWT.RESIZE //建立一个可以改变大小的窗口
    // SWT.TITLE //建立一个没有标题栏图标，没有关闭按钮的窗口
    // SWT.ON_TOP //建立一个总是在上的窗口，注意：此属性最好与CLOSE、MIN、MAX一起使用。
    // SWT.TOOL //建立一个类似工具栏的窗口
    // SWT.APPLICATION_MODAL //建立一个APPLICATION模态窗口
    // SWT.MODELESS //建立一个非模态窗口
    // SWT.PRIMARY_MODAL //建立一个PRIMARY模态窗口
    // SWT.SYSTEM_MODAL //建立一个SYSTEM模态窗口
    // 还有两个快捷属性来建立窗口
    // SHELL_TRIM //建立一个标准模式的窗口，相当于属性设置为CLOSE | TITLE | MIN | MAX | RESIZE
    // DIALOG_TRIM //建立一个对话框模式的窗口，相当于属性设置为TITLE | CLOSE | BORDER
  }

  @Override
  protected void buttonPressed(int buttonId) {
    if (IDialogConstants.CANCEL_ID == buttonId) {
      this.close();
    } else {
      super.buttonPressed(buttonId);
    }
  }

  @Override
  public boolean close() {
    if (thread != null) {
      if (thread.isAlive()) {
        MessageDialog.openWarning(getShell(), "关闭失败", "程序正在执行，不能关闭窗口！");
        return false;
      }
    }
    if (isDirty) {
      MessageBox messageBox = new MessageBox(getShell(), SWT.YES | SWT.NO | SWT.CANCEL);
      messageBox.setText("保存");
      messageBox.setMessage("是否保存变更的内容？");
      int status = messageBox.open();
      if (status == SWT.YES) {
        boolean result = save();
        if (!result) {
          return false;
        }
      } else if (status == SWT.CANCEL) {
        return false;
      }
    }
    return super.close();
  }

  protected boolean save() {
    return true;
  }

  public void setDialogId(String dialogId) {
    if (dialogId == null) {
      dialogId = BASE_DIALOG;
    } else {
      this.dialogId = dialogId;
    }
  }

  public synchronized DialogInfo getDialogInfo() {
    if (dialogInfo == null) {
      dialogInfo = DialogConfigFactory.getDialogInfo(dialogId, DialogType.JFACE);
    }
    return dialogInfo;
  }

  public void setDialogInfo(DialogInfo dialogInfo) {
    this.dialogInfo = dialogInfo;
  }

  public boolean isLockedUI() {
    return lockedUI;
  }

  public void setLockedUI(boolean lockedUI) {
    this.lockedUI = lockedUI;
  }

  public boolean isUseCustomProgressMonitorPart() {
    return useCustomProgressMonitorPart;
  }

  public void setUseCustomProgressMonitorPart(boolean useCustomProgressMonitorPart) {
    this.useCustomProgressMonitorPart = useCustomProgressMonitorPart;
  }

  public String getWindowTitle() {
    return windowTitle;
  }

  public void setWindowTitle(String windowTitle) {
    this.windowTitle = windowTitle;
  }

  public Image getWindowImage() {
    return windowImage;
  }

  public void setWindowImage(Image windowImage) {
    this.windowImage = windowImage;
  }

  public boolean isDirty() {
    return isDirty;
  }

  public void setDirty(boolean isDirty) {
    this.isDirty = isDirty;
  }

  public Thread getThread() {
    return thread;
  }

  public void setThread(Thread thread) {
    this.thread = thread;
  }

  public String getDialogId() {
    return dialogId;
  }

}
